package nc.bs.gl.glvoucher.bo.fip;

import nc.bd.accperiod.InvalidAccperiodExcetion;
import nc.bs.framework.common.NCLocator;
import nc.bs.gl.glvoucher.processor.NVoucherSupplyProcessor;
import nc.bs.gl.glvoucher.processor.fip.NVoucherSupply4FipProcessor;
import nc.bs.logging.Logger;
import nc.gl.assautoconfig.util.AssautoconfigUtil;
import nc.gl.glconst.systemtype.SystemtypeConst;
import nc.itf.glcom.para.GLParaAccessor;
import nc.pubimpl.gl.glvoucher.fip.NVoucherSumServiceImpl;
import nc.pubitf.accperiod.AccountCalendar;
import nc.pubitf.org.ICloseAccQryPubServicer;
import nc.vo.fip.external.FipBillSumRSVO;
import nc.vo.fip.external.FipSaveResultVO;
import nc.vo.fip.service.FipRelationInfoVO;
import nc.vo.fipub.utils.StrTools;
import nc.vo.gateway60.itfs.CalendarUtilGL;
import nc.vo.gl.aggvoucher.MDVoucher;
import nc.vo.gl.glvoucher.AggNVoucherVO;
import nc.vo.gl.glvoucher.NDetailVO;
import nc.vo.gl.glvoucher.NVoucherVO;
import nc.vo.gl.glvoucher.fip.NVoucherConverter;
import nc.vo.glcom.constant.GLVoucherKindConst;
import nc.vo.glcom.tools.GLPubProxy;
import nc.vo.ml.NCLangRes4VoTransl;
import nc.vo.pub.BusinessException;
import nc.vo.pub.lang.UFBoolean;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;

/**
 * 根据会计平台的FipSaveResultVO 生成凭证VO 
 * 临时凭证和正式凭证
 * @author qinhaof
 *
 */
public class NVoucherGenerator {

	/**
	 * 生成临时凭证
	 * @param saveResultVO
	 * @return
	 * @throws BusinessException
	 */
	public MDVoucher generateMDVoucher(FipSaveResultVO saveResultVO) throws BusinessException {
		MDVoucher mdvoucher = null;
		AggNVoucherVO aggvoucher = (AggNVoucherVO)saveResultVO.getBillVO();
		processVoucher(aggvoucher, saveResultVO.getMessageinfo(), true);
		if(!StrTools.isEmptyStr(saveResultVO.getMessageinfo().getPk_sumrule())) {
			saveResultVO.setBillVO(aggvoucher);
			FipBillSumRSVO sumRsVO = fipSaveVO2SumVO(saveResultVO);
			List<FipBillSumRSVO> sumRsVOs = new ArrayList<>();
	    	sumRsVOs.add(sumRsVO);
	    	String pk_sumrule = sumRsVO.getMessageinfo().getPk_sumrule();
	    	Collection<FipBillSumRSVO> sumRsVOColl = new NVoucherSumServiceImpl().querySumBill(sumRsVOs, pk_sumrule);
	    	sumRsVO = sumRsVOColl.toArray(new FipBillSumRSVO[0])[0];
	    	aggvoucher = (AggNVoucherVO)sumRsVO.getBillVO();
		}else{
			//没有合并规则则按照orderstr排序
			orderDetailByOrderStr(aggvoucher);
		}
		NVoucherSupply4FipProcessor supply4FipProcessor = new NVoucherSupply4FipProcessor(aggvoucher);
		supply4FipProcessor.process();

		mdvoucher = NVoucherConverter.convertFromAggNVoucher(aggvoucher);
		return mdvoucher;
	}
	
	public AggNVoucherVO generateAggNVoucher(FipSaveResultVO saveResultVO) throws BusinessException {
		AggNVoucherVO aggvoucher = (AggNVoucherVO)saveResultVO.getBillVO();
		processVoucher(aggvoucher, saveResultVO.getMessageinfo(), false);
		if(needCombine(saveResultVO)) {
			saveResultVO.setBillVO(aggvoucher);
			FipBillSumRSVO sumRsVO = fipSaveVO2SumVO(saveResultVO);
			List<FipBillSumRSVO> sumRsVOs = new ArrayList<>();
	    	sumRsVOs.add(sumRsVO);
	    	String pk_sumrule = sumRsVO.getMessageinfo().getPk_sumrule();
	    	Collection<FipBillSumRSVO> sumRsVOColl = new NVoucherSumServiceImpl().querySumBill(sumRsVOs, pk_sumrule);
	    	sumRsVO = sumRsVOColl.toArray(new FipBillSumRSVO[0])[0];
	    	aggvoucher = (AggNVoucherVO)sumRsVO.getBillVO();
		}
		NVoucherSupply4FipProcessor supply4FipProcessor = new NVoucherSupply4FipProcessor(aggvoucher);
		supply4FipProcessor.process();
		NVoucherSupplyProcessor supplyProcessor = new NVoucherSupplyProcessor(aggvoucher);
		supplyProcessor.processBaseInfo();
		supplyProcessor.process();
		//hrp start
		new AssautoconfigUtil().beforeSaveAutoMatchAssData(aggvoucher);
		//hrp end
		return aggvoucher;
	}
	
	//补充凭证信息
	private void processVoucher(AggNVoucherVO aggvoucher, FipRelationInfoVO msgVO, boolean isRT) throws BusinessException {
		NVoucherVO voucher = aggvoucher.getParentVO();
		NDetailVO[] details = aggvoucher.getChildrenVO();

		voucher.setPk_accountingbook(msgVO.getPk_org());
		voucher.setPk_group(msgVO.getPk_group());

		if(voucher.getPrepareddate() == null) {
			voucher.setPrepareddate(msgVO.getBusidate());
		}

		fillPeriodInfo(voucher, isRT);

		if(StrTools.isEmptyStr(msgVO.getPk_system())) {
			voucher.setPk_system(SystemtypeConst.FIP);
		}else {
			voucher.setPk_system(msgVO.getPk_system());
		}

		if(voucher.getVoucherkind() == null) {
			voucher.setVoucherkind(GLVoucherKindConst.NORMAL);
		}

		if(details != null && details.length > 0) {
			String explanation = details[0].getExplanation() == null ? NCLangRes4VoTransl.getNCLangRes().getStrByID("glnvoucher_0","0glnvoucher-0002")/*@res "外系统生成凭证"*/ : details[0].getExplanation();
			voucher.setExplanation(explanation);
		}
	}
	
	private void fillPeriodInfo(NVoucherVO voucher, boolean isRT) throws BusinessException {
		AccountCalendar calendar = CalendarUtilGL.getAccountCalendarByAccountBook(voucher.getPk_accountingbook());
		try {
			calendar.setDate(voucher.getPrepareddate());
		} catch (InvalidAccperiodExcetion e) {
			Logger.error(e.getMessage(), e);
		}

		String year = calendar.getYearVO().getPeriodyear();
		String period = calendar.getMonthVO().getAccperiodmth();

		voucher.setPeriod(period);
		voucher.setYear(year);

		if(isRT) {
			return;
		}

		UFBoolean isNextPeriod = GLParaAccessor.isVoucherNextPeriod(voucher.getPk_accountingbook());
		if(!isNextPeriod.booleanValue()) {
			voucher.setPeriod(period);
			voucher.setYear(year);
			return;
		}

		boolean isClosed = NCLocator.getInstance().lookup(ICloseAccQryPubServicer.class).isCloseByAccountBookId(voucher.getPk_accountingbook(), year + "-" + period);
		if(!isClosed) {
			voucher.setPeriod(period);
			voucher.setYear(year);
			return;
		}

		while(true) {
			calendar.roll(AccountCalendar.MONTH, 1);
			year = calendar.getYearVO().getPeriodyear();
			period = calendar.getMonthVO().getAccperiodmth();
			boolean closed = NCLocator.getInstance().lookup(ICloseAccQryPubServicer.class).isCloseByAccountBookId(voucher.getPk_accountingbook(), year + "-" + period);
			if(!closed) {
				break;
			}
		}

		 int count = GLPubProxy.getRemoteInitBalance().isBuiltByGlOrgBook(voucher.getPk_accountingbook(), year);
		 if(count == 0) {
			 throw new BusinessException(NCLangRes4VoTransl.getNCLangRes().getStrByID("glnvoucher_0","0glnvoucher-0003",null,new String[] {year})/*@res "年度{0}未建账，无法生成下期凭证！"*/);
		 }

		 voucher.setPeriod(period);
		 voucher.setYear(year);
		 voucher.setPrepareddate(calendar.getMonthVO().getBegindate());
	}
	
    private FipBillSumRSVO fipSaveVO2SumVO(FipSaveResultVO vo) {
    	FipBillSumRSVO sumVO = new FipBillSumRSVO();
    	sumVO.setBillVO(vo.getBillVO());
    	sumVO.setMessageinfo(vo.getMessageinfo());
    	return sumVO;
    }
    
	private boolean needCombine(FipSaveResultVO saveResultVO) {
		if(saveResultVO.getMessageinfo().getIsNeedCombine() == null
				|| saveResultVO.getMessageinfo().getIsNeedCombine().booleanValue()) {
			return true;
		}
		return false;
	}

	private void orderDetailByOrderStr(AggNVoucherVO aggNVoucherVO){
		NDetailVO[] detailVOS = aggNVoucherVO.getChildrenVO();
		if(detailVOS == null){
			return;
		}
		Comparator<NDetailVO> compare = (o1, o2)->{
			if(o1.getOrderstr()==null&&o2.getOrderstr()==null) {
				return 0;
			}else if(o1.getOrderstr()==null) {
				return -1;
			}else if(o2.getOrderstr()==null) {
				return 1;
			}else {
				return o1.getOrderstr().compareTo(o2.getOrderstr());
			}
		};
		Arrays.sort(detailVOS, compare);
		aggNVoucherVO.setChildrenVO(detailVOS);
	}
}
